package com.lj.dict.service.impl;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import com.lj.common.enums.ICommonEnum;
import com.lj.common.utils.ClassUtils;
import com.lj.dict.params.DictQueryParams;
import com.lj.dict.properties.DictProperties;
import com.lj.dict.result.DictItemResult;
import com.lj.dict.result.EnumDict;
import com.lj.dict.service.EnumDictService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luojing
 * @date 2024/11/15
 */
@Service
@Slf4j
public class EnumDictServiceImpl implements EnumDictService {

    @Resource
    private DictProperties dictProperties;

    /**
     * 字典名称与字典信息映射
     */
    private final Map<String, EnumDict> enumDictMap = new HashMap<>();


    @Override
    public List<EnumDict> getDict(DictQueryParams params) {
        init();
        return enumDictMap.values().stream()
                // 是空的条件就全部返回
                .filter(dict -> StrUtil.isBlank(params.getName()) || dict.getName().equals(params.getName()))
                .filter(dict -> StrUtil.isBlank(params.getValueType()) || dict.getValueType().equals(params.getValueType()))
                .collect(Collectors.toList());
    }

    @Override
    public List<DictItemResult<Object>> getDictItemByName(String dictName) {
        init();
        EnumDict enumDict = enumDictMap.get(dictName);
        if (enumDict == null) {
            return Collections.emptyList();
        }
        return enumDict.getDictItemResultList();
    }


    private void init() {
        // 双重检测
        if (CollUtil.isEmpty(enumDictMap)) {
            synchronized (EnumDictServiceImpl.class) {
                if (CollUtil.isEmpty(enumDictMap)) {
                    final TimeInterval timer = new TimeInterval();
                    log.info("加载枚举字典...");
                    loadEnumDict();
                    log.info("加载枚举字典加载完毕 共加载[{}]个枚举字典 耗时:{} ms", enumDictMap.size(), timer.intervalMs());
                }
            }
        }
    }

    private void loadEnumDict() {
        // 扫描类路径下所有 实现ICommonEnum的枚举
        Set<String> enumDictPackages = dictProperties.getEnumDictPackages();
        Set<Class<?>> enumClassSet = new HashSet<>();
        for (String enumDictPackage : enumDictPackages) {
            if (StrUtil.isBlank(enumDictPackage)) {
                continue;
            }
            enumClassSet.addAll(ClassUtil.scanPackageBySuper(enumDictPackage, ICommonEnum.class));
        }
        for (Class<?> enumClass : enumClassSet) {
            // 不是枚举的排除
            if (!ClassUtil.isEnum(enumClass)) {
                continue;
            }
            EnumDict enumDict = toEnumDictDto(enumClass);
            if (enumDict != null) {
                enumDictMap.put(enumDict.getName(), enumDict);
            }
        }
    }

    private EnumDict toEnumDictDto(Class<?> enumClass) {
        // 获取名称和描述
        String name;
        String description = "";
        com.lj.common.enums.EnumDict annotation = AnnotationUtil.getAnnotation(enumClass, com.lj.common.enums.EnumDict.class);
        if (annotation == null) {
            // 对没有加EnumDict注解的枚举,不加载
            return null;
        }
        name = annotation.name();
        if (StrUtil.isBlank(name)) {
            name = ClassUtil.getClassName(enumClass, true);
        }
        description = annotation.description();
        EnumDict temp = enumDictMap.get(name);
        if (temp != null) {
            log.warn("无法添加枚举({})作为字典,因为有与之同名的枚举({})",
                    ClassUtil.getClassName(enumClass, false), name);
            return null;
        }
        EnumDict enumDict = new EnumDict();
        enumDict.setName(name);
        enumDict.setClassName(ClassUtil.getClassName(enumClass, false));
        enumDict.setSimpleClassName(ClassUtil.getClassName(enumClass, true));
        enumDict.setDescription(description);
        // 值类型
        Class<?> valueType = getTypeArgument(enumClass);
        // 在lang包下可直接使用,所以不需要全类名
        enumDict.setValueType(ClassUtils.getClassName(valueType));
        List<DictItemResult<Object>> dictItemResultList = new ArrayList<>();
        for (Object enumConstant : enumClass.getEnumConstants()) {
            ICommonEnum<?> commonEnum = (ICommonEnum<?>) enumConstant;
            DictItemResult<Object> dictItemResult = new DictItemResult<>();
            dictItemResult.setValue(commonEnum.getValue());
            dictItemResult.setLabel(commonEnum.getDesc());
            dictItemResult.setExtendJson(commonEnum.getExtend());
            dictItemResultList.add(dictItemResult);
        }
        enumDict.setDictItemResultList(dictItemResultList);
        return enumDict;
    }

    private Class<?> getTypeArgument(Class<?> aClass) {
        ParameterizedType parameterizedType = TypeUtil.toParameterizedType(aClass, 1);
        return TypeUtil.getClass(parameterizedType.getActualTypeArguments()[0]);
    }

}
